#include <twit/resource/twit4c/JKOauth.h>
#include <liboauth/liboauth.h>
#include <curl/curl.h>

#include <string>

#if defined(DEBUG)||defined(_DEBUG)
#pragma comment(lib,"libeay32.lib")
#pragma comment(lib,"ssleay32.lib")
#pragma comment(lib,"libcurld_a.lib")
#else
#pragma comment(lib,"libeay32.lib")
#pragma comment(lib,"ssleay32.lib")
#pragma comment(lib,"libcurl_a.lib")
#endif

#pragma comment(lib,"ws2_32.lib")
#pragma comment(lib,"Wldap32.lib")

class CJKOauth
{
	std::string
		customerKey,
		customerSecret,
		accessToken,
		accessTokenSecret;
	SignatureMethod
		signMethod;
public:
	CJKOauth():signMethod(SignatureMethodHmac)
	{
		curl_global_init(CURL_GLOBAL_ALL);
	}
	~CJKOauth()
	{
		curl_global_cleanup();
	}

	void setCustomer(std::string key, std::string secret)
	{
		customerKey = key;
		customerSecret = secret;
	}

	void setAccessToken(std::string token, std::string tokenSecret)
	{
		accessToken = token;
		accessTokenSecret = tokenSecret;
	}

	void setSignatureMethod(SignatureMethod method)
	{
		signMethod = method;
	}

	bool isValidAccessToken()
	{
		return !(accessToken.empty()||accessTokenSecret.empty());
	}

	char* request(const char* uri,RequestMethod reqMethod, int* pRetCode, int* pRetHttpResponse)
	{
		if(!uri)	return NULL;

		char
			*req_url =NULL, 
			*postarg =NULL,
			*response = NULL;
		
		_FREE(response);
		
#define _CSN(str) str.empty()?NULL:str.c_str()

		req_url = oauth_sign_url2(
			uri,
			reqMethod==RequestMethodGet ? NULL:&postarg,

			(OAuthMethod)signMethod,
			reqMethod==RequestMethodGet ? "GET":"POST", 
			_CSN(customerKey),
			_CSN(customerSecret),
			_CSN(accessToken),
			_CSN(accessTokenSecret));

		if(!req_url)	return NULL;
	
		oauth_curl _perform = reqMethod==RequestMethodGet ? oauth_curl_get:oauth_curl_post;
		long httpCode=200;

		//printf("request url :\n%s\n", req_url);

		CURLcode rc = _perform(req_url, postarg, NULL, &response, &httpCode);
		_FREE(postarg);

		if(rc != CURLE_OK)
		{
			if(pRetCode) *pRetCode = rc;
			_FREE(response);
		}
		else 
		{
			if(pRetCode)
			{
				*pRetCode = httpCode!=200 ? (int)httpCode:0;
			}
		}
		if(pRetHttpResponse) *pRetHttpResponse = (int)httpCode;

		_FREE(req_url);
		return response;
	}

	char* requestStream(const char* uri, response_callback resFunc, void* userData, int* pRetCode, int* pRetHttpResponse)
	{
		if(!uri)	return NULL;

		char
			*req_url =NULL, 
			*postarg =NULL,
			*response = NULL;

		_FREE(response);

		req_url = oauth_sign_url2(
			uri,
			NULL,
			(OAuthMethod)signMethod,
			"GET", 
			_CSN(customerKey),
			_CSN(customerSecret),
			_CSN(accessToken),
			_CSN(accessTokenSecret));

		if(!req_url)	return NULL;

		long httpCode=200;

		CURLcode rc = oauth_curl_get2(req_url, &response, &httpCode, resFunc, userData);
		_FREE(postarg);

		if(rc != CURLE_OK)
		{
			if(pRetCode) *pRetCode = rc;
			_FREE(response);
		}
		else 
		{
			if(pRetCode)
			{
				*pRetCode = httpCode!=200 ? (int)httpCode:0;
			}
		}
		if(pRetHttpResponse) *pRetHttpResponse = (int)httpCode;

		_FREE(req_url);
		return response;
	}
};

BOOL JKOauth_isValidAccessToken(JKOauth h)
{
	return ((CJKOauth*)h)->isValidAccessToken()?TRUE:FALSE;
}

JKOauth JKOauth_create()
{
	return (JKOauth)(new CJKOauth);
}
void JKOauth_destroy(JKOauth* p)
{
	if(p && *p)
	{
		delete (CJKOauth*)*p;
		*p = NULL;
	}
}

void JKOauth_setCustomer(JKOauth h, const char* key, const char* secret)
{
	((CJKOauth*)h)->setCustomer(key?key:"", secret?secret:"");
}

void JKOauth_setAccessToken(JKOauth h, const char* token, const char* tokenSecret)
{
	((CJKOauth*)h)->setAccessToken(token?token:"", tokenSecret?tokenSecret:"");
}

void JKOauth_setSignatureMethod(JKOauth h, SignatureMethod method)
{
	((CJKOauth*)h)->setSignatureMethod(method);
}

char* JKOauth_request(JKOauth h, const char* uri,RequestMethod reqMethod, int* pRetCode, int* pRetHttpResponse)
{
	return ((CJKOauth*)h)->request(uri, reqMethod, pRetCode, pRetHttpResponse);
}

char* JKOauth_requestStream(JKOauth h, const char* uri, response_callback resFunc, void* userData, int *pRetCode, int* pRetHttpResponse)
{
	return ((CJKOauth*)h)->requestStream(uri, resFunc, userData, pRetCode, pRetHttpResponse);
}

void JKOauth_free(void** pp)
{
	if(pp)	_FREE(*pp);
}

int JKOauth_splitUrlParameter(const char* src, char*** rv)
{
	int rc;
	rc = oauth_split_url_parameters(src, rv);
	qsort(*rv, rc, sizeof(char *), oauth_cmpstringp);
	if(rc<=0) return 0;
	return rc;
}

void JKOauth_freeUrlparameter(char** rv, int size)
{
	if(rv)
	{
		if(size>0)
		{
			for(int i=0; i<size; i++)
			{
				free((void*)rv[i]);
			}
		}
		free((void*)rv);
	}
}